﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Cci.Contracts;
using System.IO;
using CSharpSourceEmitter;
using Microsoft.Cci.Contrib.Mutators;
using Microsoft.Cci.ILToCodeModel;
using Microsoft.Cci.MutableCodeModel;

namespace Microsoft.Cci.Contrib.PeToText
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                Console.WriteLine("usage: pe2pe [path]fileName.ext");
                return;
            }
            bool noIL = args.Length == 2;
            HostEnvironment host = new HostEnvironment();
            var module = host.LoadUnitFrom(args[0]) as IAssembly;
            if (module == null || module == Dummy.Module || module == Dummy.Assembly)
            {
                Console.WriteLine(args[0] + " is not a PE file containing a CLR module or assembly.");
                return;
            }
            PdbReader pdbReader = null;
            string pdbFile = Path.ChangeExtension(module.Location, "pdb");
            if (File.Exists(pdbFile))
            {
                Stream pdbStream = File.OpenRead(pdbFile);
                pdbReader = new PdbReader(pdbStream, host);
            }

            ContractProvider contractProvider = new ContractProvider(new ContractMethods(host));
            var xSourceMethodBodyProvider = new SourceMethodBodyProvider(delegate(IMethodBody body)
            {
                return new ILToCodeModel.SourceMethodBody(body, host, contractProvider, pdbReader);
            });
            var xSourceMethodToIlConverter = new SourceToILConverterProvider(delegate
            {
                return new CodeModelToILConverter(host, pdbReader, contractProvider);
            });

            var xCopier = new CodeModelNormalizer(host, true, xSourceMethodBodyProvider, xSourceMethodToIlConverter, pdbReader, contractProvider);
            var xModule = xCopier.GetMutableCopy(module);
            xModule = xCopier.Visit(xModule);
            var xForStatementMutator = new ForStatementMutator(host);
            xModule = xForStatementMutator.Visit(xModule);
            var xForEachStatementMutator = new ForEachStatementMutator(host);
            xModule = xForEachStatementMutator.Visit(xModule);

            SourceEmitterContext sourceEmitterContext = new SourceEmitterContext();
            SourceEmitterOutputString sourceEmitterOutput = new SourceEmitterOutputString(sourceEmitterContext);
            global::PeToText.SourceEmitter csSourceEmitter = new global::PeToText.SourceEmitter(sourceEmitterOutput, host, contractProvider, pdbReader, noIL);

            csSourceEmitter.Visit((INamespaceDefinition)xModule.UnitNamespaceRoot);
            string txtFile = Path.ChangeExtension(pdbFile, "txt");
            File.WriteAllText(txtFile, sourceEmitterOutput.Data);


        }
    }

    internal class HostEnvironment : MetadataReaderHost
    {
        PeReader peReader;
        internal HostEnvironment()
        {
            this.peReader = new PeReader(this);
        }

        public override IUnit LoadUnitFrom(string location)
        {
            IUnit result = this.peReader.OpenModule(BinaryDocument.GetBinaryDocumentForFile(location, this));
            this.RegisterAsLatest(result);
            return result;
        }

    }
}
